package com.whc.gulimall.cart.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.whc.common.utils.R;
import com.whc.gulimall.cart.constant.CartConstant;
import com.whc.gulimall.cart.feign.ProductFeign;
import com.whc.gulimall.cart.interceptor.CartInterceptor;
import com.whc.gulimall.cart.service.CartService;
import com.whc.gulimall.cart.vo.Cart;
import com.whc.gulimall.cart.vo.CartItem;
import com.whc.gulimall.cart.vo.ProductInfoVo;
import com.whc.gulimall.cart.vo.UserInfoTo;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;


/**
 * 购物车 ServiceImpl
 *
 * @author angaoen
 */
@Service
public class CartServiceImpl implements CartService {

    @Resource(name = "stringRedisTemplate")
    private StringRedisTemplate redisTemplate;

    /**
     * 商品服务远程调用
     */
    @Resource
    private ProductFeign productFeign;

    /**
     * 线程池
     */
    @Resource
    private ThreadPoolExecutor executors;

    /**
     * 添加商品到购物车列表
     *
     * @param skuId skuId
     * @param count 商品数
     * @return 封装好的商品属性
     */
    @Override
    public void addToCart(Long skuId, Integer count) throws ExecutionException, InterruptedException {
        BoundHashOperations<String, Object, Object> hashOps = getHashOps();

        // 获取数据库中是否已存在此商品
        String str = (String) hashOps.get(skuId.toString());
        // 判断
        if (StrUtil.isBlank(str)) {
            CartItem cartItem = new CartItem();
            cartItem.setCount(count);
            cartItem.setSkuId(skuId);

            CompletableFuture<Void> skuInfoFuture = CompletableFuture.runAsync(() -> {
                // 根据skuId查询商品信息
                R info = productFeign.info(skuId);
                if (info.getCode() == 0) {
                    // 类型转换
                    ProductInfoVo skuInfo = info.getData("skuInfo", new TypeReference<ProductInfoVo>() {
                    });
                    cartItem.setImage(skuInfo.getSkuDefaultImg());
                    cartItem.setPrice(skuInfo.getPrice());
                    cartItem.setTitle(skuInfo.getSkuTitle());
                }
            }, executors);

            CompletableFuture<Void> skuAttrValueListFuture = CompletableFuture.runAsync(() -> {
                R r = productFeign.listSkuAttrValueBySkuId(skuId);
                if (r.getCode() == 0) {
                    cartItem.setSkuAttr(r.getData(new TypeReference<List<String>>() {
                    }));
                }
            }, executors);

            CompletableFuture.allOf(skuInfoFuture, skuAttrValueListFuture).get();

            hashOps.put(skuId.toString(), JSON.toJSONString(cartItem));
        } else {
            // 已存在此商品
            CartItem cartItem = JSON.parseObject(str, new TypeReference<CartItem>() {
            });
            // 重新设置商品数量
            cartItem.setCount(cartItem.getCount() + count);
            hashOps.put(skuId.toString(), JSON.toJSONString(cartItem));
        }
    }

    /**
     * 通过skuId获取商品信息
     *
     * @param skuId skuId
     * @return 商品信息
     */
    @Override
    public CartItem getCartItemBySkuId(Long skuId) {
        BoundHashOperations<String, Object, Object> hashOps = getHashOps();
        String str = (String) hashOps.get(skuId.toString());
        return StrUtil.isNotBlank(str)
                ? JSON.parseObject(str, new TypeReference<CartItem>() {
        })
                : null;
    }

    /**
     * 获取购物车列表
     *
     * @return 购物车列表对象
     */
    @Override
    public Cart cartListPage() {
        // 判断是临时用户还是会员
        UserInfoTo userInfo = CartInterceptor.threadLocal.get();

        // 首先尝试获取会员的购物车商品
        if (userInfo.getUserId() != null) {
            List<CartItem> vipCartItems = getCartItems(userInfo.getUserId().toString());
            // 会员购物车不为空
            if (CollUtil.isNotEmpty(vipCartItems)) {
                // 获取临时购物车
                if (StrUtil.isNotBlank(userInfo.getUserKey())) {
                    List<CartItem> tempCartItems = getCartItems(userInfo.getUserKey());
                    if (CollUtil.isNotEmpty(tempCartItems)) {
                        // 需要把临时购物车中可能出现的商品添加到vip商品中
                        Map<Long, CartItem> tempCartItemMap = tempCartItems.stream().collect(Collectors
                                .toMap(CartItem::getSkuId, item -> item));
                        for (CartItem vipCartItem : vipCartItems) {
                            if (tempCartItemMap.get(vipCartItem.getSkuId()) != null) {
                                Long skuId = vipCartItem.getSkuId();
                                vipCartItem.setCount(vipCartItem.getCount() + tempCartItemMap.get(skuId).getCount());
                                tempCartItemMap.remove(skuId);
                            }
                        }
                        vipCartItems.addAll(tempCartItemMap.values());
                    }
                }

                // 存放数据库
                BoundHashOperations<String, Object, Object> hashOps = getHashOps();
                hashOps.putAll(vipCartItems.stream().collect(Collectors
                        .toMap(item -> item.getSkuId().toString(), JSON::toJSONString)));
                // 清理临时购物车数据
                deleteCartItemByCartKey(userInfo.getUserKey());
                Cart cart = new Cart();
                cart.setCartItems(vipCartItems);
                return cart;
            }
            // 没有登录账号
        } else {
            if (StrUtil.isNotBlank(userInfo.getUserKey())) {
                List<CartItem> tempCartItems = getCartItems(userInfo.getUserKey());
                if (CollUtil.isNotEmpty(tempCartItems)) {
                    Cart cart = new Cart();
                    cart.setCartItems(tempCartItems);
                    return cart;
                }
            }
        }
        return null;
    }

    /**
     * 更换商品的选中状态
     *
     * @param skuId   skuId
     * @param checked 1-选中 0-未选中
     */
    @Override
    public void checkItem(Long skuId, Integer checked) {
        CartItem cartItem = getCartItemBySkuId(skuId);
        cartItem.setChecked(checked == 1);
        BoundHashOperations<String, Object, Object> hashOps = getHashOps();
        hashOps.put(skuId.toString(), JSON.toJSONString(cartItem));
    }

    /**
     * 更改商品的数量
     *
     * @param skuId skuId
     * @param count 商品数量
     */
    @Override
    public void countItem(Long skuId, Integer count) {
        CartItem cartItem = getCartItemBySkuId(skuId);
        if (cartItem != null) {
            cartItem.setCount(count);
            BoundHashOperations<String, Object, Object> hashOps = getHashOps();
            hashOps.put(skuId.toString(), JSON.toJSONString(cartItem));
        }
    }

    /**
     * 商品指定skuId的商品
     *
     * @param skuId skuId
     */
    @Override
    public void deleteItem(Long skuId) {
        BoundHashOperations<String, Object, Object> hashOps = getHashOps();
        hashOps.delete(skuId.toString());
    }

    /**
     * 获取购物车列表
     *
     * @return 购物车商品
     */
    @Override
    public List<CartItem> listProductList() {
        UserInfoTo userInfoTo = CartInterceptor.threadLocal.get();
        if (userInfoTo.getUserId() != null) {
            List<CartItem> cartItems = getCartItems(userInfoTo.getUserId().toString());
            if (CollUtil.isNotEmpty(cartItems)) {
                cartItems = cartItems.stream().filter(CartItem::getChecked).collect(Collectors.toList());
                R r = productFeign.listSkuPricesByIds(cartItems.stream().map(CartItem::getSkuId)
                        .collect(Collectors.toList()));
                if (r.getCode() == 0) {
                    Map<Long, BigDecimal> priceMap = r.getData(new TypeReference<Map<Long, BigDecimal>>() {
                    });
                    if (CollUtil.isNotEmpty(priceMap)) {
                        for (CartItem cartItem : cartItems) {
                            cartItem.setPrice(priceMap.get(cartItem.getSkuId()));
                        }
                    }
                }
            }
            return cartItems;
        }
        return null;
    }

    /**
     * 根据cartKey删除数据
     *
     * @param cartKey 名
     */
    private void deleteCartItemByCartKey(String cartKey) {
        redisTemplate.delete(CartConstant.CART_PREFIX + cartKey);
    }

    /**
     * 获取redis Hash操作对象
     *
     * @return Hash操作对象
     */
    private BoundHashOperations<String, Object, Object> getHashOps() {
        // 首先要判断是否是用户还是临时账号
        UserInfoTo userInfoTo = CartInterceptor.threadLocal.get();

        // 创建统一hash存储名
        String key;
        if (userInfoTo.getUserId() == null) {
            // 没有userId，说明是临时用户
            key = CartConstant.CART_PREFIX + userInfoTo.getUserKey();
        } else {
            // 会员
            key = CartConstant.CART_PREFIX + userInfoTo.getUserId();
        }
        return redisTemplate.boundHashOps(key);
    }

    /**
     * 通过 cartKey获取商品列表
     *
     * @param cartKey cartKey
     * @return 商品列表
     */
    private List<CartItem> getCartItems(String cartKey) {
        BoundHashOperations<String, Object, Object> hashOps = redisTemplate
                .boundHashOps(CartConstant.CART_PREFIX + cartKey);
        List<Object> values = hashOps.values();
        return CollUtil.isNotEmpty(values)
                ? values.stream().map(item -> JSON.parseObject((String) item, new TypeReference<CartItem>() {
        })).collect(Collectors.toList())
                : null;
    }
}
